use std::{env, num::ParseIntError};

use rand::Rng;

fn main() {
  let exec_code = env::args().nth(1).expect("no code need to run");
  match exec_code.as_str() {
    "1" => test1(),
    "2" => test2(),
    "3" => {
      let num = Some(5);
      let nil: Option<i32> = None;
      test3(num);
      test3(nil);
    },
    "4" => test4(),
    "5" => test5(),
    "6" => test6(),
    "7" => {test7();},
    "8" => test8(),
    _ => (),
  }
}

// 1.类型&变量
fn test1() {
  // 有符号整数（signed integers）：i8、i16、i32、i64、i128 和 isize（指针宽度）
  // 无符号整数（unsigned integers）： u8、u16、u32、u64、u128 和 usize（指针宽度）
  // 浮点数（floating point）： f32、f64
  // char（字符）：单个 Unicode 字符，如 'a'，'α' 和 '∞'（每个都是 4 字节）
  // bool（布尔型）：只能是 true 或 false
  // 单元类型（unit type）：()。其唯一可能的值就是 () 这个空元组
  // 数组（array）：如 [1, 2, 3]
  // 元组（tuple）：如 (1, true)

  // 变量可以给出类型说明。
  let _logical: bool = true;

  let _a_float: f64 = 1.0;  // 常规说明
  let _an_integer = 5i32; // 后缀说明

  // 否则会按默认方式决定类型。
  let _default_float = 3.0; // `f64`
  let _default_integer = 7;   // `i32`

  // 类型也可根据上下文自动推断。
  let mut inferred_type = 12; // 根据下一行的赋值推断为 i64 类型
  inferred_type = 4294967296i64;

  // 可变的（mutable）变量，其值可以改变。
  let mut mutable = 12; // Mutable `i32`
  mutable = 21;

  // 报错！变量的类型并不能改变。
  // mutable = true;

  // 但可以用遮蔽（shadow）来覆盖前面的变量。
  let mutable = true;

  println!("{1}, {0}", inferred_type, mutable);
}

// 2.流程控制
fn test2() {
  let number = 11;

  println!("Tell me about {}", number);
    match number {
      // 匹配单个值
      1 => println!("One!"),
      // 匹配多个值
      2 | 3 | 5 | 7 | 11 => println!("This is a prime"),
      // 试一试 ^ 将 13 添加到质数列表中
      // 匹配一个闭区间范围
      13..=19 => println!("A teen"),
      // 处理其他情况
      _ => println!("Ain't special"),
      // 试一试 ^ 注释掉这个总括性的分支
    }
}

// 3.空值
fn test3(num: Option<i32>) {
  // enum Option<T> {
  //   None,
  //   Some(T),
  // }
  match num {
    Some(val) => println!("{}", val),
    None => println!("null"),
  }
  if let Some(val) = num {
    println!("{}", val);
  } else {
    println!("null");
  }
}


fn takes_ownership(some_string: &mut String) { // some_string 进入作用域
  some_string.push_str(" world");
  println!("str print in {}", some_string);
} // 这里，some_string 移出作用域并调用 `drop` 方法。
// 占用的内存被释放

fn makes_copy(some_integer: i32) { // some_integer 进入作用域
  println!("num print in {}", some_integer);
} // 这里，some_integer 移出作用域。没有特殊之处

// 4.所有权
fn test4() {
  // Rust 中的每一个值都有一个 所有者（owner）
  // 值在任一时刻有且只有一个所有者
  // 当所有者（变量）离开作用域，这个值将被丢弃

  let mut s = String::from("hello");  // s 进入作用域

  takes_ownership(&mut s);        // s 的值移动到函数里 ...
  println!("str print out {}", s);       // ... 所以到这里不再有效
  let x = 5;                        // x 进入作用域
  makes_copy(x);            // x 应该移动函数里，
  println!("num print out {}", x);       // 但 i32 是 Copy 的，
                                         // 所以在后面可继续使用 x
} // 这里，x 先移出了作用域，然后是 s。但因为 s 的值已被移走，不会再处理

fn multiply(first_number_str: &str, second_number_str: &str) -> i32 {
  // panic!("AAAaaaaa!!!!");
  // 我们试着用 `unwrap()` 把数字放出来。它会咬我们一口吗？
  let first_number = first_number_str.parse::<i32>().unwrap();
  let second_number = second_number_str.parse::<i32>().unwrap();
  first_number * second_number
}

fn _multiply2(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
  // panic!("AAAaaaaa!!!!");
  // 我们试着用 `unwrap()` 把数字放出来。它会咬我们一口吗？
  let first_number = first_number_str.parse::<i32>()?;
  let second_number = second_number_str.parse::<i32>()?;
  Ok(first_number * second_number)
}

// 5.异常处理
fn test5() {
  let twenty = multiply("10", "2");
  println!("double is {}", twenty);

  let tt = _multiply2("t", "2");
  if let Ok(t) = tt {
    println!("double is {}", t);
  }
  // println!("double is {}", tt);
}

struct Droppable {
  name: &'static str,
}

// 这个简单的 `drop` 实现添加了打印到控制台的功能。
impl Drop for Droppable {
  fn drop(&mut self) {
      println!("> Dropping {}", self.name);
  }
}

// 6.资源回收
fn test6() {
  let _a = Droppable { name: "a" };

  // 代码块 A
  {
      let _b = Droppable { name: "b" };

      // 代码块 B
      {
          let _c = Droppable { name: "c" };
          let _d = Droppable { name: "d" };

          println!("Exiting block B");
      }
      println!("Just exited block B");

      println!("Exiting block A");
  }
  println!("Just exited block A");

  // 变量可以手动使用 `drop` 函数来销毁。
  // drop(_a);
  // 试一试 ^ 将此行注释掉。

  println!("end of the main function");

  // `_a` *不会*在这里再次销毁，因为它已经被（手动）销毁。
}

// 7.文档
/// method will return num 3
/// 
/// # Examples
/// ```
/// let ret = demo::test7();
/// assert_eq!(ret, 3);
/// ```
fn test7() -> u32 {
  3
}

fn test8() {
  let mut names = vec!["董昆山", "皇甫国贝", "李俊仁", "李连斯", "李忠宇", "吕强", "吕万杰", "马菁", "邱建婷", "王龙", "王杏杏", "王悦", "周志鹏"];
  let mut i = 0;
  loop {
    let mut rng = rand::thread_rng();
    let len = names.len() as i32;
    println!("{}", len);
    let index: i32 = rng.gen_range(0..len);
    println!("{}", index);
    let ret = names.remove(index as usize);
    println!("{}", ret);
    i += 1;
    if i == 4 {
      break;
    }
  }
}

// 8.测试
#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn on_result() {
    assert_eq!(test7(), 3);
  }
}
